package cn.xyfmzmy.spring.web;

import cn.xyfmzmy.spring.BeanPostProcessor;
import cn.xyfmzmy.spring.Componet;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

/**
 * 负责请求分发
 */
@Componet
public class DispatcherServlet extends HttpServlet implements BeanPostProcessor {

    // key:请求的uri    value:封装了相关信息的WebHandler
    private Map<String, WebHandler> handlerMap = new HashMap<>();

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 根据request获取handler，handler里封装了controller,method等信息
        WebHandler handler = findHandler(req);
        if (handler == null) {
            resp.setContentType("text/html;charset=UTF-8");
            resp.getWriter().write("<h1>Error 你的请求没有对应的处理器!</h1> <br> ");
            return;
        }
        try {
            // 获取对应的controller对象
            Object controllerBean = handler.getControllerBean();
            // 解析对应方法的参数
            Object[] args = resolveArgs(req, handler.getMethod());
            // 执行对应方法
            Object result = handler.getMethod().invoke(controllerBean, args);
            // 根据返回类型进行返回
            switch (handler.getResultType()) {
                case HTML -> {
                    resp.setContentType("text/html;charset=UTF-8");
                    resp.getWriter().write(result.toString());
                }
                case JSON -> {
                    resp.setContentType("application/json;charset=UTF-8");
                    resp.getWriter().write(JSONObject.toJSONString(result));
                }
                case LOCAL -> {
                    ModelAndView mv = (ModelAndView) result;
                    String view = mv.getView();
                    InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(view);
                    try (resourceAsStream){
                        String html = new String(resourceAsStream.readAllBytes());
                        html = renderTemplate(html,mv.getContext());  // 自定义模版引擎，根据mv的上下文进行渲染
                        resp.setContentType("text/html;charset=UTF-8");
                        resp.getWriter().write(html);
                    }
                }
            }

        } catch (Exception e) {
            throw new ServletException(e);
        }

    }

    // 自定义模版引擎，根据mv的上下文内容进行渲染
    private String renderTemplate(String html, Map<String, String> context) {
        // 简单写，直接把{}替换为name
        String replaceHtml = html.replaceAll("\\{\\}", context.get("name"));
        return replaceHtml;
    }

    // 解析对应方法的参数
    private Object[] resolveArgs(HttpServletRequest req, Method method) {
        Parameter[] parameters = method.getParameters();
        Object[] args = new Object[parameters.length];
        for (int i = 0; i < parameters.length; i++) {
            Parameter parameter = parameters[i];
            String value = null;
            // 通过@Param注解获取参数名
            Param param = parameter.getAnnotation(Param.class);
            if (param != null) {
                value = req.getParameter(param.value());
            } else {
                value = req.getParameter(parameter.getName());
            }

            Class<?> parameterType = parameter.getType();
            if (String.class.isAssignableFrom(parameterType)) {
                args[i] = value;
            } else if (Integer.class.isAssignableFrom(parameterType)) {
                args[i] = Integer.parseInt(value);
            } else {
                args[i] = null;
            }
        }
        return args;
    }

    // 根据uri获取handler
    private WebHandler findHandler(HttpServletRequest req) {
        return handlerMap.get(req.getRequestURI());
    }

    @Override
    public Object afterInitializeBean(Object bean, String beanName) {
        // 填充handlerMap
        if (!bean.getClass().isAnnotationPresent(Controller.class)) {
            // 没有@Controller直接返回
            return bean;
        }
        // 获取类上@RequestMapping的值
        RequestMapping classRm = bean.getClass().getAnnotation(RequestMapping.class);
        String classUrl = classRm != null ? classRm.value() : "";
        Arrays.stream(bean.getClass().getDeclaredMethods())
                .filter(m -> m.isAnnotationPresent(RequestMapping.class))
                .forEach(m -> {
                    // 获取方法上的@RequestMapping
                    RequestMapping methodRm = m.getAnnotation(RequestMapping.class);
                    // 拼接uri
                    String key = classUrl.concat(methodRm.value());
                    WebHandler webHandler = new WebHandler(bean, m);
                    if (handlerMap.put(key, webHandler) != null) {
                        throw new RuntimeException("请求路径定义重复：" + key);
                    }
                });
        return bean;
    }
}
